package com.mybatis.demo.plugin;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author zhangyan
 * @version $ Id: MyProxy3.java, v 0.1 2020/10/12 15:33 zhangyan Exp $
 */
public class MyProxy3 {
  public static void main(String[] args) {
    HelloService service = new HelloServiceImpl();
    TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
    service = (HelloService) transactionInterceptor.plugin(service);
    LogInterceptor interceptor = new LogInterceptor();
    service = (HelloService) interceptor.plugin(service);
    service.sayHello("1");
  }

  /**
   * 接口
   */
  public interface HelloService {
    void sayHello(String a);

  }

  /**
   * 实现类
   */
  static class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello(String a) {
      System.out.println("sayHello......"+a);
    }
  }

  /**
   * 自定义代理类执行方法
   */
  static class HWInvocationHandler implements InvocationHandler {
    //目标类
    private Object target;

    /**
     * 拦截器
     */
    private Interceptor interceptor;

    public HWInvocationHandler(Object target, Interceptor interceptor) {
      this.target = target;
      this.interceptor = interceptor;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      Invocation invocation = new Invocation(target, method, args);
      System.out.println("new Invocation()" + invocation.hashCode());
      return interceptor.intercept(invocation);
    }

    public static Object wrap(Object target, Interceptor interceptor) {
      HWInvocationHandler hwInvocationHandler = new HWInvocationHandler(target, interceptor);
      return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), hwInvocationHandler);
    }
  }

  /**
   * 封装目标类属性
   */
  static class Invocation {

    private Object target;

    private Method method;

    private Object[] args;

    public Invocation(Object target, Method method, Object[] args) {
      this.target = target;
      this.method = method;
      this.args = args;
    }

    /**
     * 执行目标类方法
     *
     * @return
     * @throws Throwable
     */
    public Object process() throws Throwable {
      System.out.println("执行目标类方法");
      return method.invoke(target, args);
    }

  }

  public interface Interceptor {
    /**
     * 具体拦截处理
     */
    Object intercept(Invocation invocation);

    /**
     * 插入目标类
     */
    Object plugin(Object target);
  }

  static class LogInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) {
      System.out.println("Invocation的值" + invocation.hashCode());
      System.out.println("------aaaaaaaaaaaaaaaaaa-------------");
      try {
        Object obj = invocation.process();
        System.out.println("------bbbbbbbbbbbbbbbbbbbbbbb-------------");
        return obj;
      } catch (Throwable throwable) {
        throwable.printStackTrace();
      }

      return null;
    }

    @Override
    public Object plugin(Object target) {
      return HWInvocationHandler.wrap(target, this);
    }
  }

  static class TransactionInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) {
      System.out.println("Invocation的值" + invocation.hashCode());
      System.out.println("------ccccccccccccccccccccccc-------------");
      try {
        Object obj = invocation.process();
        System.out.println("------dddddddddddddddddddddddd-------------");
        return obj;
      } catch (Throwable throwable) {
        throwable.printStackTrace();
      }
      return null;
    }

    @Override
    public Object plugin(Object target) {
      return HWInvocationHandler.wrap(target, this);
    }
  }
}
